# external interface for all kinds of types


from abc import ABC, abstractmethod
from bcat.gtp.serde.dev2.impl.bytes_reader import BytesReader
class IValidator(ABC):
    def from_str(self, s, codec='utf-8') -> bool:
        return self.from_bytes(s.encode(codec))
        
    def from_bytes(self, in_bytes) -> bool:
        return self.from_reader(BytesReader(in_bytes))

    @abstractmethod
    def from_reader(self, reader) -> bool:
        pass


from bcat.gtp.serde.error import UnexpectEndOfStreamError
from bcat.gtp.serde.dev2.impl.deserializer import Deserializer
class Validator(IValidator):
    def from_reader(self, reader) -> bool:
        deserializer = Deserializer.from_reader(reader)
        result = self._validate(deserializer)
        if not deserializer.is_end():
            raise UnexpectEndOfStreamError(deserializer.reader().position())
        return result

    @abstractmethod
    def _validate(self, deserializer):
        pass



from bcat.gtp.serde.dev2.valid.impl.validates import ValidateKey
class Key(Validator):
    def _validate(self, deserializer):
        return ValidateKey().validate(deserializer)

from bcat.gtp.serde.dev2.valid.impl.validates import ValidateBytes
class Bytes(Validator):
    def _validate(self, deserializer):
        return ValidateBytes().validate(deserializer)
        
from bcat.gtp.serde.dev2.valid.impl.validates import ValidateDict
class Dict(Validator):
    def _validate(self, deserializer):
        return ValidateDict().validate(deserializer)
        



from bcat.gtp.serde.error import NeedAlphaError, NeedDigitError, UnexpectEndOfStreamError, NeedEqualSignError
import unittest
class TestKey(unittest.TestCase):
    def test_main(self):
        self.assertTrue(Key().from_str("X01"))
        self.assertTrue(Key().from_str('x02'))

        self.assertRaises(UnexpectEndOfStreamError, Key().from_str, *('',))
        self.assertRaises(NeedAlphaError, Key().from_str, *('1',))
        self.assertRaises(UnexpectEndOfStreamError, Key().from_str, *('X',))
        self.assertRaises(NeedDigitError, Key().from_str, *('Xa',))
        self.assertRaises(UnexpectEndOfStreamError, Key().from_str, *('X1',))
        self.assertRaises(NeedDigitError, Key().from_str, *('X1a',))
        self.assertRaises(UnexpectEndOfStreamError, Key().from_str, *('X11a',))
    

from bcat.gtp.serde.error import NeedAlphaError, NeedDigitError, NeedOpenBracesError, UnexpectEndOfStreamError
import unittest
class TestDict(unittest.TestCase):
    def test_main(self):
        self.assertTrue(Dict().from_str("{X01=X02}"))
        self.assertRaises(UnexpectEndOfStreamError, Dict().from_str, *("",))
        self.assertRaises(UnexpectEndOfStreamError, Dict().from_str, "{X01=")
        self.assertRaisesRegex(NeedEqualSignError, "=", Dict().from_str, "{X01,")
        self.assertRaisesRegex(NeedEqualSignError, "=", Dict().from_str, "{X01[")
        self.assertRaisesRegex(NeedEqualSignError, "=", Dict().from_str, "{X01]")
        self.assertRaisesRegex(NeedEqualSignError, "=", Dict().from_str, "{X01{")
        self.assertRaisesRegex(NeedEqualSignError, "=", Dict().from_str, "{X01}")
        #self.assertTrue(Dict().from_str("{X01["))
        #TODO: more exception cases

import unittest
class TestBytes(unittest.TestCase):
    def test_main(self):
        self.assertTrue(Bytes().from_str("Xdddddd"))
        self.assertTrue(Bytes().from_str("Xd\\\\xx\\,xx\\=xx\\[xx\\]xx\\{xx\\}"))

        self.assertRaises(Exception, Bytes().from_str, *("Xddddd,",))
